import { NodeTypes } from "./NodeTypes";
import { ParallelNode } from "./controls/ParallelNode";
import { FallbackNode } from "./controls/FallbackNode";
import { SequenceNode } from "./controls/SequenceNode";
import { INode } from "./interfaces/INode";
import { IfThenElseNode } from "./controls/IfThenElseNode";
import { ReactiveSequence } from "./controls/ReactiveSequence";
import { SequenceStarNode } from "./controls/SequenceStarNode";
import { ReactiveFallback } from "./controls/ReactiveFallback";
import { WhileDoElseNode } from "./controls/WhileDoElseNode";
import { DelayNode } from "./decorators/DelayNode";
import { ForceFailureNode } from "./decorators/ForceFailureNode";
import { ForceSuccessNode } from "./decorators/ForceSuccessNode";
import { InverterNode } from "./decorators/InverterNode";
import { RepeatNode } from "./decorators/RepeatNode";
import { RetryNode } from "./decorators/RetryNode";
import { TimeOutNode } from "./decorators/TimeOutNode";
import { KeepRunningUntilFailureNode } from "./decorators/KeepRunningUntilFailureNode";
import { INodeConfig } from "./interfaces/INodeConfig";
import { ControlNode } from "./controls/ControlNode";
import { DecoratorNode } from "./decorators/DecoratorNode";


export class BehaviorTreeFactory {
    /**初始化 */
    private static inited: boolean = false;

    private static class_map: Map<string, new (name: string, blackboard: any) => INode<any>> = new Map<string, new (name: string, blackboard: any) => INode<any>>();

    static Init(): void {
        if (this.inited) {
            return;
        }

        this.Register(NodeTypes.SEQUENCE, SequenceNode);
        this.Register(NodeTypes.ReactiveSequence, ReactiveSequence);
        this.Register(NodeTypes.SequenceStar, SequenceStarNode);

        this.Register(NodeTypes.PARALLEL, ParallelNode);
        this.Register(NodeTypes.FALLBACK, FallbackNode);
        this.Register(NodeTypes.ReactiveFallback, ReactiveFallback);

        this.Register(NodeTypes.IfThenElseNode, IfThenElseNode);
        this.Register(NodeTypes.WhileDoElseNode, WhileDoElseNode);

        this.Register(NodeTypes.Delay, DelayNode);
        this.Register(NodeTypes.ForceFailure, ForceFailureNode);
        this.Register(NodeTypes.ForceSuccess, ForceSuccessNode);
        this.Register(NodeTypes.KeepRunningUntilFailure, KeepRunningUntilFailureNode);
        this.Register(NodeTypes.Inverter, InverterNode);
        this.Register(NodeTypes.Repeat, RepeatNode);
        this.Register(NodeTypes.Retry, RetryNode);
        this.Register(NodeTypes.TimeOut, TimeOutNode);
        this.inited = true;
    }

    /**
     * 注册节点类
     * @param name 
     * @param clazz 
     */
    static Register<T>(name: string, clazz: new (name: string, blackboard: T) => INode<T>): void {
        this.class_map.set(name.toLocaleLowerCase(), clazz);
    }

    /**
     * 注销节点类
     * @param name 
     */
    static Unregister(name: string): void {
        this.class_map.delete(name.toLocaleLowerCase());
    }

    /**
     * 创建节点
     * @param data 
     * @returns 
     */
    static CreateNode<T>(data: INodeConfig, blackboard: T): INode<T> {
        this.Init();
        const clazz = this.class_map.get(data.type.toLocaleLowerCase());
        if (!clazz) {
            throw new Error(`${data.name}节点不存在`);
        }
        let result = new clazz(data.name, blackboard);
        result.Init(data);
        const isControl = result instanceof ControlNode;
        const isDecorator = result instanceof DecoratorNode;
        if (data.children) {
            for (let index = 0; index < data.children.length; index++) {
                const child_data = data.children[index];
                if (isControl) {
                    result.AddChild(this.CreateNode(child_data, blackboard));
                }
                if (isDecorator) {
                    result.SetChild(this.CreateNode(child_data, blackboard));
                }
            }
        }
        return result;
    }
}